package com.zpyr.common;

import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.log4j.Logger;

public class UploadUtil {
	static Logger logger = Logger.getLogger(UploadUtil.class);	// TODO:mall 나중에 삭제
	
	/**
	 * (파일업로드) 파일을 업로드하고 업로드된 파일명 리스트를 반환한다. (같은 이름의 파일이 있으면 이름을 변경함)
	 * Collection에 Map으로 저장함.
	 * <li>file_name: 파일명
	 * <li>file_size: 파일사이즈
	 * <li>file_ext: 확장자
	 * @param fileDir 저장될 파일 경로
	 * @param items List<FileItem>
	 * @return Collection
	 * @throws Exception
	 */
	public static boolean checkSize(String fileDir, List items , long maxSize) {
		Iterator iter = items.iterator();
		
		FileItem item;
		while(iter.hasNext()) {
			item = (FileItem)iter.next();
			if (!item.isFormField()) {
					if( maxSize < item.getSize() ) {
						return false;
					}
			}
		}
		return true;
	}
	
	public static Collection saveFiles(String fileDir, List items) throws Exception {
		Iterator iter;
		ArrayList fileList = new ArrayList();

		String filename = "";
		String fileExt = "";
		
		if (!fileDir.endsWith("/")) {
			fileDir += "/";
		}

		// 디렉토리가 존재하지 않으면 생성
		File dir = new File(fileDir);
		if (!dir.exists()) {
			dir.mkdirs();
		}

		// 실제 파일 업로드
		iter = items.iterator();
		while (iter.hasNext()) {
			FileItem item = (FileItem) iter.next();

			if (!item.isFormField()) {
				if (item.getSize() > 0) {
					filename = getFilename(item.getName());
					File file = getNewFile(new File(fileDir + filename)); // 서버에 존재하지 않는 새 파일명을 가져온다.
					item.write(file);

					logger.debug("...getContentType:" + item.getContentType());
					filename = file.getName();
					fileExt = getFileExt(filename);
					Map map = new HashMap();
					map.put("file_name", filename);
					map.put("file_size", String.valueOf(item.getSize()));
					map.put("file_ext", fileExt);
					// 이미지일 경우에 width, heigh를 가져온다.
					//					if (item.getContentType().indexOf("image") != -1) {
					//						map.put("img_width", );
					//						map.put("img_height", );
					//					}

					fileList.add(map);
				}
			}
		}
		return fileList;
	}
	
	/**
	 * (파일업로드) 이미 존재하지 않는 새 파일명을 가져온다.
	 * @param f
	 * @return File
	 */
	public static File getNewFile(File f) {
		String name = f.getName();
		String body = null;
		String ext = null;

		int dot = name.lastIndexOf(".");
		if (dot != -1) {
			body = name.substring(0, dot);
			ext = name.substring(dot); // includes "."
		} else {
			body = name;
			ext = "";
		}

		int count = 0;
		while (f.exists() && count < 99) {
			count++;
			String newName = body + count + ext;
			f = new File(f.getParent(), newName);
			logger.debug("# new filename:" + f.getName());
		}

		return f;
	}

	/**
	 * (파일업로드) 파일 삭제
	 * @param fileDir
	 * @param list
	 * @throws Exception
	 */
	public static void deleteFiles(String fileDir, ArrayList list) {
		if (list == null || list.size() == 0)
			return;

		if (fileDir.charAt(fileDir.length() - 1) != '/')
			fileDir += "/";

		String filename = "";
		
		try {
			for (int i = 0; i < list.size(); i++) {
				filename = fileDir + (String) list.get(i);
	
				File file = new File(filename);
				file.delete();
			}
		} catch (Exception ignored) { }
	}

	/**
	 * (파일업로드) 단일 파일 삭제
	 * @param fileDir 파일경로
	 * @param filename 파일명
	 */
	public static void deleteFile(String fileDir, String filename) {
		if (fileDir.charAt(fileDir.length() - 1) != '/') {
			fileDir += "/";
		}
		
		deleteFile(fileDir + filename);
	}
	
	/**
	 * (파일업로드) 단일 파일 삭제
	 * @param filepath 파일 풀네임
	 */
	public static void deleteFile(String filepath) {
		try {
			File file = new File(filepath);
			file.delete();
		} catch (Exception ignored) { }
	}
	
	/**
	 * 파일경로+파일명에서 파일명을 추출한다.
	 * @param fullName
	 * @return String
	 */
	public static String getFilename(String fullName) {
		if (fullName == null)
			return "";

		fullName = replace(fullName, "\\", "/");

		String fileName = "";

		if (fullName.lastIndexOf('/') == -1)
			fileName = fullName;
		else
			fileName = fullName.substring(fullName.lastIndexOf('/') + 1, fullName.length());

		return fileName;
	}
	
	/**
	 * 파일경로+파일명에서 확장자를 추출한다.
	 * @param fileName
	 * @return String
	 */
	public static String getFileExt(String fileName) {
		if (fileName == null)
			return "";

		String fileExt = "";

		if (fileName.lastIndexOf('.') == -1)
			fileExt = "";
		else
			fileExt = fileName.substring(fileName.lastIndexOf('.') + 1, fileName.length());

		return fileExt;
	}
	
	/**
	 * 문자열중 일부를 다른 문자열로 치환한다.
	 * @param origin 원본 문자열
	 * @param source 치환할 문자열
	 * @param target 치환될 문자열
	 * @return String
	 */
	public static String replace(String origin, String source, String target) {
		if (origin == null)
			return "";

		int itmp = 0;
		String tmp = origin;
		StringBuffer sb = new StringBuffer("");

		while (tmp.indexOf(source) > -1) {
			itmp = tmp.indexOf(source);
			sb.append(tmp.substring(0, itmp));
			sb.append(target);
			tmp = tmp.substring(itmp + source.length());
		}
		sb.append(tmp);

		return sb.toString();
	}
	
	/**
	 * multipart 데이터인 경우 request 객체의 변수, 값 쌍을 Map에 담는다.
	 * 주의 : 같은 이름의 파라미터가 여러개 올 경우는 맵의 특성상 하나만 저장됨
	 * @param request
	 * @return Map
	 * @throws Exception
	 */
	public static Map getMapFromMulti(HttpServletRequest request) throws Exception {
		FileItemFactory factory = new DiskFileItemFactory(); 		// Create a factory for disk-based file items
		ServletFileUpload upload = new ServletFileUpload(factory); 	// Create a new file upload handler
		
		String encoding = request.getCharacterEncoding();
		upload.setHeaderEncoding(encoding);
		
		List /* FileItem */ items = upload.parseRequest(request); 	// Parse the request

		Iterator iter = items.iterator();
		Map map = new HashMap();
		String name = "";
		String value = "";
		
		while (iter.hasNext()) {
		    FileItem item = (FileItem) iter.next();

		    if (item.isFormField()) {
				name = item.getFieldName();
				value = item.getString(encoding);
		    } else {
		    	name = item.getFieldName();
		    	value = StringUtil.getFilename(item.getName());
		    }
			
			map.put(name, value);
			logger.debug("#... name:["+name+"], value:["+value+"]");
		}
		
		return map;
	}

	/**
	 * multipart 데이터인 경우 request 객체의 변수, 값 쌍을 Map에 담는다.
	 * 같은 이름의 파라미터가 여러개 올 경우는 맵의 특성상 하나만 저장됨
	 * @param iter
	 * @return Map
	 * @throws Exception
	 */
	public static Map getMapFromMulti(Iterator iter) throws Exception {
		return getMapFromMulti(iter, "UTF-8");
	}
	
	/**
	 * multipart 데이터인 경우 request 객체의 변수, 값 쌍을 Map에 담는다.
	 * 같은 이름의 파라미터가 여러개 올 경우는 맵의 특성상 하나만 저장됨
	 * @param iter
	 * @param encoding
	 * @return Map
	 * @throws Exception
	 */
	public static Map getMapFromMulti(Iterator iter, String encoding) throws Exception {
		Map map = new HashMap();

		String name = "";
		String value = "";
		
		while (iter.hasNext()) {
		    FileItem item = (FileItem) iter.next();

		    if (item.isFormField()) {
				name = item.getFieldName();
				value = item.getString(encoding);
		    } else {
		    	name = item.getFieldName();
		    	value = StringUtil.getFilename(item.getName());
		    }
			
			map.put(name, value);
			logger.debug("#... name:["+name+"], value:["+value+"]");
		}
		
		return map;
	}

	/**
	 * 같은 이름으로 넘어오는 파라미터가 여러개일 경우 값들을 가져온다.
	 * @param key 가져올 파라미터
	 * @param items List<FileItem>
	 * @return Collection
	 * @throws Exception
	 */
	public static Collection getValuesFromMulti(String key, List items) throws Exception {
		return getValuesFromMulti(key, items, "UTF-8");
	}

	/**
	 * 같은 이름으로 넘어오는 파라미터가 여러개일 경우 값들을 가져온다.
	 * @param key 가져올 파라미터
	 * @param items List<FileItem>
	 * @param encoding
	 * @return Collection
	 * @throws Exception
	 */
	public static Collection getValuesFromMulti(String key, List items, String encoding) throws Exception {
		Iterator iter;
		ArrayList fileList = new ArrayList();

		String name = "";
		String value = "";
		
		iter = items.iterator();
		while (iter.hasNext()) {
			FileItem item = (FileItem) iter.next();
			name = item.getFieldName();
			
			if (name.equals(key)) {
				if (item.isFormField()) {
					value = item.getString(encoding);
				} else {
					if (item.getSize() > 0) {
						value = StringUtil.getFilename(item.getName());
					}
				}
				fileList.add(value);
			}
		}
		
		return fileList;
	}
}
